fix: vuln correlation fixes - #2582
Conversation
Reviewer's GuideThis PR ensures CPE-only SBOM components (nodes with no PURL but with CPE that matches vulnerabilities) are correctly surfaced in advisory and vulnerability detail endpoints instead of being silently dropped, by making qualified_purl optional across the Rust models and SQL, relaxing joins/filters, and emitting empty purl arrays when appropriate. File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="modules/fundamental/src/sbom/model/details.rs" line_range="53" />
<code_context>
Ok(Self {
advisory_id: res.try_get("", "advisory_id")?,
- qualified_purl_id: res.try_get("", "qualified_purl_id")?,
+ qualified_purl_id: res.try_get("", "qualified_purl_id").ok(),
sbom_id: res.try_get("", "sbom_id")?,
sbom_node_id: res.try_get("", "node_id")?,
</code_context>
<issue_to_address>
**issue (bug_risk):** Using `.ok()` here converts all DB errors (not just NULLs) into `None`, potentially hiding genuine query/schema issues.
If you only want to map NULLs to `None`, consider using `try_get::<Option<Uuid>>` (if available) or explicitly handling `DbErr::RecordNotFound`/NULL. The current `.ok()` call turns any failure to read `qualified_purl_id` (including type/column errors) into `None`, which can hide real bugs and lead to inconsistent data.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
|
@rh-jfuller Shouldn't this PR include some tests to prove the list and detail endpoints produce consistent results for CPE only and CPE + PURL components? |
… backlink endpoints
SBOM list endpoint correctly counts vulnerabilities matched via
package level CPE identity (cpe_status) on nodes without a PURL but
both detail endpoints silently dropped them:
- /sbom/{id}/advisory: cpe_advisory_info_sql() filtered out rows /w
NULL qualified_purl_id and IdSet required it to be non-optional Uuid
- /vulnerability/{id}: cpe_status sub-query INNER JOINed
sbom_node_purl_ref and qualified_purl eliminating CPE-only nodes
This causes list page to show higher vuln count detail pages
…ysis get_product_statuses_for_purl joins version_range but never applies version_matches(), returning all version ranges for package name regardless of whether queried version falls within range or uses a compatible version scheme which causes false-positive vuln match This commit passes pURL version into get_product_statuses_for_purl and add version_matches(purl_version, version_range.*) filter, matching pattern already used by sibling purl_status query
get_product_statuses_for_purl returns product statuses without checking whether the advisory's CPE context applies to the SBOMs containing the queried PURL. Add the same three-way CPE context filter already used by the sibling purl_status query: allow when context_cpe_id is NULL, when it matches the SBOM's describing CPEs, or when the SBOM has no describing CPEs.
|
@SourceryAI summary |
|
@SourceryAI guide |
Add three tests exercising CPE-context and purl-less CPE node handling in
SBOM advisory correlation, with CycloneDX fixtures under
etc/test-data/cyclonedx/TC-5630.
- sbom_details_purlless_cpe_node_consistency (passing): guards the fix for
a vulnerability matched only via a package-level CPE on a component with a
CPE but no PURL. Asserts the three views agree: /sbom/{id}/advisory lists
it, the SBOM list severity counts match, and /vulnerability/{id} backlinks
the SBOM. Uses the opentofu SBOM (purl-less os:hummingbird node) and a
synthetic CVE-2026-12151 matching cpe:/a:redhat:hummingbird:1
- sbom_details_wrong_product_cpe_context (#[ignore])
- sbom_details_wrong_product_satellite (#[ignore])
The two reproducers are ignored so CI stays green; remove #[ignore] once
context scoping derives product identity from the OS/root component CPE.
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.4.z
git worktree add -d .worktree/backport-2582-to-release/0.4.z origin/release/0.4.z
cd .worktree/backport-2582-to-release/0.4.z
git switch --create backport-2582-to-release/0.4.z
git cherry-pick -x bcf709a1aa94ed4d1204cdb6fa3e6b3cf3844e7d 0dcab72d80bc7266db5a61823619b69894caa6b0 b9eddf35bcee7335f6e58ba39a764f63f19789d3 21960720482cd1872e0e550b35eac358cde98a95 0c5ede8eb9a8253d0567ad35b7dda43bd5e50abb 02aa413dbeea925f778af1b3d9647d54384f3f3e 610b122b1a1049693eeb66ea3093d4c3cb132b09 |
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.5.z
git worktree add -d .worktree/backport-2582-to-release/0.5.z origin/release/0.5.z
cd .worktree/backport-2582-to-release/0.5.z
git switch --create backport-2582-to-release/0.5.z
git cherry-pick -x bcf709a1aa94ed4d1204cdb6fa3e6b3cf3844e7d 0dcab72d80bc7266db5a61823619b69894caa6b0 b9eddf35bcee7335f6e58ba39a764f63f19789d3 21960720482cd1872e0e550b35eac358cde98a95 0c5ede8eb9a8253d0567ad35b7dda43bd5e50abb 02aa413dbeea925f778af1b3d9647d54384f3f3e 610b122b1a1049693eeb66ea3093d4c3cb132b09 |
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.4.z
git worktree add -d .worktree/backport-2582-to-release/0.4.z origin/release/0.4.z
cd .worktree/backport-2582-to-release/0.4.z
git switch --create backport-2582-to-release/0.4.z
git cherry-pick -x bcf709a1aa94ed4d1204cdb6fa3e6b3cf3844e7d 0dcab72d80bc7266db5a61823619b69894caa6b0 b9eddf35bcee7335f6e58ba39a764f63f19789d3 21960720482cd1872e0e550b35eac358cde98a95 0c5ede8eb9a8253d0567ad35b7dda43bd5e50abb 02aa413dbeea925f778af1b3d9647d54384f3f3e 610b122b1a1049693eeb66ea3093d4c3cb132b09 |
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.6.z
git worktree add -d .worktree/backport-2582-to-release/0.6.z origin/release/0.6.z
cd .worktree/backport-2582-to-release/0.6.z
git switch --create backport-2582-to-release/0.6.z
git cherry-pick -x bcf709a1aa94ed4d1204cdb6fa3e6b3cf3844e7d 0dcab72d80bc7266db5a61823619b69894caa6b0 b9eddf35bcee7335f6e58ba39a764f63f19789d3 21960720482cd1872e0e550b35eac358cde98a95 0c5ede8eb9a8253d0567ad35b7dda43bd5e50abb 02aa413dbeea925f778af1b3d9647d54384f3f3e 610b122b1a1049693eeb66ea3093d4c3cb132b09 |
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.5.z
git worktree add -d .worktree/backport-2582-to-release/0.5.z origin/release/0.5.z
cd .worktree/backport-2582-to-release/0.5.z
git switch --create backport-2582-to-release/0.5.z
git cherry-pick -x bcf709a1aa94ed4d1204cdb6fa3e6b3cf3844e7d 0dcab72d80bc7266db5a61823619b69894caa6b0 b9eddf35bcee7335f6e58ba39a764f63f19789d3 21960720482cd1872e0e550b35eac358cde98a95 0c5ede8eb9a8253d0567ad35b7dda43bd5e50abb 02aa413dbeea925f778af1b3d9647d54384f3f3e 610b122b1a1049693eeb66ea3093d4c3cb132b09 |
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.6.z
git worktree add -d .worktree/backport-2582-to-release/0.6.z origin/release/0.6.z
cd .worktree/backport-2582-to-release/0.6.z
git switch --create backport-2582-to-release/0.6.z
git cherry-pick -x bcf709a1aa94ed4d1204cdb6fa3e6b3cf3844e7d 0dcab72d80bc7266db5a61823619b69894caa6b0 b9eddf35bcee7335f6e58ba39a764f63f19789d3 21960720482cd1872e0e550b35eac358cde98a95 0c5ede8eb9a8253d0567ad35b7dda43bd5e50abb 02aa413dbeea925f778af1b3d9647d54384f3f3e 610b122b1a1049693eeb66ea3093d4c3cb132b09 |
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.4.z
git worktree add -d .worktree/backport-2582-to-release/0.4.z origin/release/0.4.z
cd .worktree/backport-2582-to-release/0.4.z
git switch --create backport-2582-to-release/0.4.z
git cherry-pick -x bcf709a1aa94ed4d1204cdb6fa3e6b3cf3844e7d 0dcab72d80bc7266db5a61823619b69894caa6b0 b9eddf35bcee7335f6e58ba39a764f63f19789d3 21960720482cd1872e0e550b35eac358cde98a95 0c5ede8eb9a8253d0567ad35b7dda43bd5e50abb 02aa413dbeea925f778af1b3d9647d54384f3f3e 610b122b1a1049693eeb66ea3093d4c3cb132b09 |
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.5.z
git worktree add -d .worktree/backport-2582-to-release/0.5.z origin/release/0.5.z
cd .worktree/backport-2582-to-release/0.5.z
git switch --create backport-2582-to-release/0.5.z
git cherry-pick -x bcf709a1aa94ed4d1204cdb6fa3e6b3cf3844e7d 0dcab72d80bc7266db5a61823619b69894caa6b0 b9eddf35bcee7335f6e58ba39a764f63f19789d3 21960720482cd1872e0e550b35eac358cde98a95 0c5ede8eb9a8253d0567ad35b7dda43bd5e50abb 02aa413dbeea925f778af1b3d9647d54384f3f3e 610b122b1a1049693eeb66ea3093d4c3cb132b09 |
|
Backport failed for Please cherry-pick the changes locally and resolve any conflicts. git fetch origin release/0.6.z
git worktree add -d .worktree/backport-2582-to-release/0.6.z origin/release/0.6.z
cd .worktree/backport-2582-to-release/0.6.z
git switch --create backport-2582-to-release/0.6.z
git cherry-pick -x bcf709a1aa94ed4d1204cdb6fa3e6b3cf3844e7d 0dcab72d80bc7266db5a61823619b69894caa6b0 b9eddf35bcee7335f6e58ba39a764f63f19789d3 21960720482cd1872e0e550b35eac358cde98a95 0c5ede8eb9a8253d0567ad35b7dda43bd5e50abb 02aa413dbeea925f778af1b3d9647d54384f3f3e 610b122b1a1049693eeb66ea3093d4c3cb132b09 |
Contains various vuln correlation fixes which all have to be done together as there are multiple codepaths influencing each other.
Vulnerability correlation has at least 5 distinct query paths that should produce consistent results:
Plus the associated vuln analysis with each has its own filter logic (version matching, CPE context, deprecation), implemented independently.
We will address above multiple codepaths in future PRs, this set of fixes maintains status quo.
include CPE-only SBOM nodes in advisory detail and vulnerability backlink endpoints
The affected-vulnerability count for an SBOM is inconsistent across endpoints. A vuln matching an SBOM only through a package-level CPE (on a component with no PURL) is counted by the list query but
silently dropped by both detail endpoints:
The discrepancy appears when an SBOM contains a purl-less CPE component whose CPE matches vulnerabilities via
cpe_status.Both detail endpoints required matched SBOM nodes to have a
qualified_purl_id:cpe_advisory_info_sql()had an explicitWHERE p.qualified_purl_id IS NOT NULLfilter.INNER JOIN sbom_node_purl_refand
INNER JOIN qualified_purl, eliminating CPE-only nodes.IdSet/QueryCatcher/SbomStatusCatcherall declaredqualified_purlas mandatory, so even if the SQL returned NULLs thedeserialization would fail.
fwiw - list endpoint's counting CTE had no such requirement, producing correct (higher) count.
Fix
IS NOT NULLfilter fromcpe_advisory_info_sql()INNER JOIN→LEFT JOINforsbom_node_purl_refandqualified_purlin the vulnerability detail cpe_status queryqualified_purloptional inIdSet,QueryCatcher, andSbomStatusCatcherpurlarray for CPE-only packages instead of skippingentire row
which fixes TC-5630
add version_matches filter to product status query for PURL analysis
fixes TC-5170
add CPE context filter to product status query for PURL analysis
fixes TC-5171
Summary by Sourcery
Include CPE-only SBOM components in vulnerability and advisory detail results.
Bug Fixes:
Enhancements:
Summary by Sourcery
Fix vulnerability correlation results for CPE-only SBOM components and context-aware PURL product statuses.
Bug Fixes:
Enhancements: